7.03. Забота о коде и данных
Защита кода
Когда пишется код, он должен сохраняться в локальном файле в хранилище. Однако, никто из нас не защищён от непредвиденных ситуаций:
- Несохранённые изменения – допустим, работа велась без автосохранения, или IDE была закрыта случайно или из-за ошибки;
- Сбой системы – отключение электричества, синий экран смерти (BSOD), зависание операционной системы;
- Проблема с инфраструктурой – сбой сервера, проблема с диском;
- Перезапись файлов – случайное сохранение старой версии поверх новой (к примеру, случайно скопировали некорректный текст и сохранили файл).
- Удаление папок или файлов без возможности восстановления;
- Ошибочная замена файлов;
- Конфликт изменений из-за одновременной работы с файлом (когда разработчики №1 и №2 работали одновременно, будет сохранена версия последнего, без учёта первого).
Для защиты кода используется автосохранение (в первую очередь), снимки состояний, локальные истории и конечно же самое важное – VCS (version control system), система контроля версий.
*Контроль версий – процесс обеспечения учёта вносимых изменений с возможностью отмены изменений и отката к предыдущей версии.
Системы контроля версий — это программное обеспечение, которое помогает вам отслеживать изменения, которые вы вносите в свой код с течением времени. Когда вы редактируете свой код, вы говорите системе контроля версий сделать снимок ваших файлов. Система контроля версий сохраняет этот снимок навсегда, чтобы вы могли вызвать его позже, если он вам понадобится. Используйте контроль версий, чтобы сохранять свою работу и координировать изменения кода в вашей команде.
★ Самая популярная система контроля версий – Git (гит) – децентрализованная система контроля версий с распределенной архитектурой, позволяющая каждому разработчику обладать своей локальной копией всей истории разработки.

Git использует хеши SHA-1 (алгоритм криптографического шифрования), а с 2020 года перешел на SHA-256, хеш вычисляется не только от содержимого файла, но и от метаданных (размера, типа объекта). Технологии шифрования, которые используются для идентификации подлинности объектов, позволяют эффективно сравнивать хеш-таблицы файлов и обеспечивать контроль изменений.
Git используется через инструменты (можно назвать их Git-системами). Их можно разделить на два вида – платформы и клиенты.
Платформы позволяют использовать хостинг репозиториев. ★ GitLab – платформа для хостинга Git-репозиториев с расширенными возможностями (CI/CD, Issue Tracking, Wiki и прочее):
- можно установить на свой сервер и настроить под себя;
- встроенный CI/CD (устанавливается пайплайн);
- Issue Tracker (трекер задач);
- Container Registry (для Docker-образов). ★ GitHub – целая соцсеть, самый популярный хостинг Git-репозиториев, принадлежит Microsoft:
- встроенный CI/CD (GitHub Actions);
- Pull Requests (PR) – код-ревью перед слиянием;
- GitHub Pages (хостинг статических сайтов);
- Социальная сеть для разработчиков (именно там размещают open-source проекты). ★ Bitbucket – облачный сервис для хостинга репозиториев, созданный компанией Atlassian:
- ограниченная бесплатная версия (до 5 пользователей);
- интеграция с проектами Atlassian (Confluence (документация), Jira (привязка коммитов к задачам), Trello (управление задачами));
- Bitbucket Pipelines – CI/CD для автоматической сборки и деплоя;
- поддержка Mercurial – альтернативной системы контроля версий;
- Code Review и Pull Request.
Мы уже затрагивали историю развития системы контроля версий. На практике можно встретить некоторые из них, и даже устаревшие.
RCS — Revision Control System хранит историю по одному файлу, использует файлы с суффиксом «,v» (например, file.txt,v).
CVCS — Centralized Version Control Systems (Централизованные) это CVS, Subversion и Perforce. Все данные хранятся на сервере. Пользователь делает checkout → изменяет → commit. Нет локальной истории: если сервер сломается — теряется всё.
DVCS — Distributed Version Control Systems (Распределённые) не только Git. Есть ещё несколько.
Perforce (CVCS) - коммерческая система, широко используется в крупных компаниях (игровые студии, банки и т.д.), поддерживает большие бинарные файлы, отлично масштабируется, имеет мощный интерфейс и интеграции. Платная и сложная.
Mercurial (DVCS) более легкий, базирован на Python, является аналогом Git, но чуть проще. Подходит для маленьких и средних проектов, имеет меньше инструментов и интеграций.
Bazaar (DVCS) разработан Canonical (Ubuntu), поддерживает как децентрализованный, так и централизованный стиль работы. Может работать поверх других систем (Git, SVN), но сейчас мало кто его использует.
Darcs (DVCS) имеет оригинальный подход к отслеживанию изменений — оперирует патчами, а не коммитами. Почти не используется в промышленной разработке, имеет мало инструментов и плохую интеграцию, однако концепция у него интересная.
BitKeeper (DVCS) была одна из первых распределённых систем, быстрая, надёжная, использовалась для разработки Linux до появления Git. Но после появления Git практически вышла из употребления.
★ Клиенты позволяют взаимодействовать с платформами, и отличаются друг от друга графическим интерфейсом.
★ Командная строка (Git Bash, PowerShell) – самый гибкий способ работы с Git. Git устанавливается на компьютер, и интегрируется в командную строку, что позволяет выполнять операции путем ввода команд.
★ TortoiseGit – графический клиент Git для Windows, который интегрируется в проводник. В отличие от классического Git, он не требует командной строки, а изменения визуализируются. Для новичков – очень легко.
★ GitKraken – кроссплатформенный клиент с красивой визуализацией веток, с поддержкой GitHub/GitLab/Bitbucket.
★ SourceTree (от Atlassian) – бесплатный клиент с графическим интерфейсом, поддерживающий интеграцию с Jira и Bitbucket.
Авторизация в Git проходит весьма интересным образом.
PAT (Personal Access Token) представляет собой альтернативу паролю при работе с GitHub, GitLab и т.д., может иметь ограниченные права и срок действия, используется вместо пароля при HTTPS-подключении.
git clone https://github.com/username/repo.git
Username: ваш-логин
Password: ваш-PAT
Получить можно на GitHub: Settings → Developer settings → Personal access tokens

SSH-ключи - другой способ, подразумевающий асинхронное шифрование (публичный + приватный ключ), испольуемое при работе через SSH-протокол.
Создаются ключи, публичный ключ привязывается к аккаунту на GitHub/GitLab, и репозиторий клонируется через SSH:
git clone git@github.com:username/repo.git

Git Credential Manager (GCM) третий способ. Инструмент, который интегрируется в Git и сохраняет токены/PAT в Credential Manager.
Windows предоставляет систему управления учётными данными — Credential Manager (Диспетчер учетных данных).
Панель управления → Учетные записи пользователей → Диспетчер учетных данных
Там хранятся логины и пароли для веб-сайтов, сетевых ресурсов (UNC-пути), приложений, поддерживается Windows Hello, сертификаты, ключи и т.д.

Git использует именно этот механизм, когда вы включаете GCM.
Внутри Windows использует:
- LSA Secrets (Local Security Authority Secrets) - защищённая часть реестра, где хранятся локальные секреты;
- DPAPI (Data Protection API) для шифрования данных на уровне пользователя или машины, и Git использует именно это;
- CredMan (Credential Manager API) для работы с сохранёнными учетными данными - там хранятся логин и токены.
Как работает Git?
★ Основные компоненты Git:
- Рабочий каталог или рабочая директория (Working Directory) - текущая директория с файлами проекта, где создаются, изменяются, удаляются файлы. Собственно, папка нашего проекта.
- .git (Git Directory) - скрытая папка в корне проекта, которая содержит всю историю изменений, метаданные и настройки репозитория. Именно здесь хранится информация о коммитах, ветках, и других элементах.
- Индекс (Staging Area) - промежуточная зона между рабочим каталогом и репозиторием, куда добавляются изменения перед тем, как их зафиксировать в коммите. Индекс позволяет контролировать, какие изменения войдут в следующий коммит.
- Коммит - зафиксированное состояние рабочего каталога, снимок изменений.
- Удалённый репозиторий (Remote Repository), расположенный на внешнем сервере (например, GitHub, GitLab, Bitbucket). Удалённый репозиторий используется для совместной работы и резервного копирования кода.
- Ветки (branch) - указатели на снимок изменений. Коммитов может быть много, и они могут быть как в одной ветке, где один коммит следует за другим, как в простом линейном алгоритме, а могут быть во множестве веток.
- HEAD - указатель на текущий коммит или ветку, в которой находимся. HEAD показывает, где вы сейчас в истории проекта. К примеру, если находимся в ветке main, то HEAD указывает на последний коммит этой ветки. При переключении на другую ветку, указатель перемещается на последний коммит этой ветки.
- Теги используются для пометки важных моментов в истории проекта. К примеру, релизы определённой версии (v1.0.0). Теги - неизменяемые маркеры конкретного коммита.
- Комментарий (Message) - описывает, какие изменения были сделаны. Это для понимания других разработчиков. Структура комментария включает заголовок (первую строку), тело и футер (опционально). Всё это указывается после параметра -m в кавычках.

Ветки бывают базовыми, основными и прочими. Название ветки - уникальный идентификатор, который помогает различать разные линии разработки.
Можно давать свои названия ветки при создании. Пример - main. Давайте разберём.
- Base - базовая ветка, относительно которой происходит изменение.
- Master/Main - основная ветка проекта, представляет собой стабильную версию кода, готовую к выпуску.
- Origin - стандартное имя для удалённого репозитория. Используется для обозначения главного источника кода.
Итого, чтобы отправить изменения в ветку main удалённого репозитория, будет выполняться команда git push origin main - то есть, указывается приложение git, команда push, репозиторий origin, ветка main.
Также бывают и прочие ветки - feature для разработки новый «фич», release для подготовки нового релиза, hotfix для быстрого исправления критических ошибок.

★ Как работает Git?
Принцип прост:
- есть четыре типа объектов – файл (blob), дерево (tree, совокупность файлов), коммит (commit, дерево и дополнительная информация) и тег (tag, указатели на коммит);
- создаётся локальный репозиторий (подкаталог .git с файлами конфигурации, журналов в каталоге проекта) на рабочем месте, через команду git init;
- при необходимости выделения файлов, и папок которые не нужно загружать в репозиторий, создаётся файл .gitignore;
- создаётся удаленный (онлайн) репозиторий, куда загружается первая версия кода путём фиксации состояния (commit) – при этом создаётся первая ветка (branch);
- на рабочем месте можно скопировать код из удаленного репозитория через команду git clone;
- создаётся дополнительная ветка (git branch);
- при создании новой версии производится фиксация изменений(commit) в выбранную ветку
- система управления версиями позволяет команде определять, какая из веток является основной (актуальной, master);
- для того, чтобы синхронизировать локальный репозиторий с удаленным, нужно выполнить push (англ. «толкать», отправить в удаленный с локального) или pull (англ. «тянуть» загрузить себе в локальный с удаленного);
- для загрузки с удаленного на локальный репозиторий свежих изменений использовать можно fetch (для загрузки изменений без изменения рабочего каталога) и pull (с автоматическим слиянием в текущую ветку).
- для объединения веток используется процедура слияния – merge для публичных веток, с созданием нового коммита слияния, и rebase для локальной очистки истории перед merge.

merge объединяет изменения из одной ветки в другую, создавая новый коммит слияния (merge commit), история становится нетипичной (ветвистой), но сохраняется оригинальная история изменений. К примеру, после checkout main можно выполнить merge feature-branch. Это важно, когда работаете с общей (публичной) веткой (main, develop) и при слиянии Pull Request'ов в GitHub/GitLab.
rebase переносит ваши коммиты «поверх» другой ветки, как будто вы их написали поверх последних изменений. Здесь наоборот, сначала checkout feature-branch, потом git rebase main. Это перезаписывает историю — опасно, если ветка уже отправлена на удалённый репозиторий. Нужно принудительно пушить (git push --force), что может сломать работу других. Это можно использовать на локальных/приватных ветках, пока никто не использует ваш код, и чтобы поддерживать актуальную историю перед отправкой PR.
Не используйте rebase на общих (публичных) ветках — это может сломать историю у других участников проекта.
При попытках merge/rebase могут быть конфликты слияния, когда Git не удалось автоматически разрешить различия в одном и том же месте файла. В таком случае нужно вручную исправить конфликт.
При необходимости точно проконтролировать и отправить только определенное измененное содержимое, используется индекс (Staging Area) для точечной отправки в коммит. Допустим. если изменены файлы A, B, C, но нужно отправить только A, B, то к коммиту можно подготовить git add A B, таким образом отправить лишь их.
Теги используются для маркировки определённых моментов в истории, чаще всего — выпусков (например, версии v1.0.0). К примеру,
git tag -a v1.0.0 -m "Release version 1.0.0"
Ветки (branches) от тегов (tags) отличаются тем, что ветка – подвижный указатель, а тег – постоянный и неподвижный. Это механизм ссылок (references). Тег может быть легковесным (только версия, git tag v1.0.0), или аннотированный, с сообщением (git tag -a v1.0.1 -m “Комментарий”).
git stash сохраняет незавершённые изменения, чтобы можно было переключиться на другую задачу. К примеру:
git stash save "Work in progress"
Потом можно применить stash:
git stash apply
Увидеть список сохранённых изменений можно через команду:
git stash list
git cherry-pick переносит один конкретный коммит из одной ветки в другую по хэшу.
git cherry-pick abc1234
здесь abc1234 — хэш нужного коммита. Можно применять, когда нужно взять только одно исправление из другой ветки или быстро исправить баг без слияния всей ветки.
git commit --amend изменяет последний коммит: можно добавить файлы или изменить сообщение
Установка Git
Windows
- Официальный дистрибутив: Git for Windows (включает Git Bash,
git.exe,ssh,scp,curlи др.). - Альтернативы: установка через пакетные менеджеры (
winget install Git.Git,scoop install git,choco install git). - Для интеграции в Windows Terminal или PowerShell рекомендуется использовать
Git Bashили настроитьPATHвручную.
Linux
- Устанавливается через системный пакетный менеджер:
- Debian/Ubuntu:
sudo apt install git - RHEL/Fedora:
sudo dnf install git - Arch:
sudo pacman -S git
- Debian/Ubuntu:
- Для получения свежей версии — сборка из исходников или использование репозиториев от разработчиков Git.
macOS
- Через официальный установщик с git-scm.com.
- Через Homebrew:
brew install git - Системная версия (
/usr/bin/git) устаревает быстро; рекомендуется использовать свежую версию из Homebrew.
Настройка Git
Настройки хранятся в трёх областях:
- Системные (
/etc/gitconfig) — для всех пользователей. - Глобальные (
~/.gitconfigили~/.config/git/config) — для текущего пользователя. - Локальные (
.git/config) — для конкретного репозитория.
Основные команды:
git config --global user.name "Имя Фамилия"
git config --global user.email "email@example.com"
git config --global init.defaultBranch main
git config --global core.editor "code --wait" # или vim, nano и т.д.
git config --global core.autocrlf input # macOS/Linux
git config --global core.autocrlf true # Windows
Дополнительно:
- Настройка внешнего инструмента для diff/merge (
difftool,mergetool). - Включение цветного вывода:
git config --global color.ui auto.
Создание репозитория
-
Новый локальный репозиторий:
mkdir project && cd project
git init -
Клонирование существующего репозитория:
git clone <url> [<directory>] -
Привязка к удалённому репозиторию (если создан локально):
git remote add origin <url>
git push -u origin main
Запись изменений в репозиторий
Базовый цикл:
- Изменение файлов в рабочей директории.
- Индексация (
git add <file>илиgit add .). - Фиксация (
git commit -m "message"). - Отправка (
git push).
Дополнительно:
git status— просмотр состояния рабочей директории и индекса.git diff— просмотр неиндексированных изменений.git diff --cached— просмотр изменений в индексе.git restore/git restore --staged— отмена изменений (начиная с Git 2.23).
Работа с GitHub: краткий гайд
-
Аутентификация:
- Через HTTPS: с использованием Personal Access Token (PAT) вместо пароля (с августа 2021).
- Через SSH: генерация ключа (
ssh-keygen), добавление публичного ключа в GitHub → Settings → SSH.
-
Типичный workflow:
git clone git@github.com:user/repo.git
cd repo
git checkout -b feature-x
# правки → add → commit
git push origin feature-x
# создаём Pull Request через веб-интерфейс -
Синхронизация с
main:git checkout main
git pull origin main
git checkout feature-x
git rebase main # или git merge main -
Удаление ветки после слияния:
git push origin --delete feature-x
git branch -d feature-x
Git-атрибуты
Файл .gitattributes определяет поведение Git для конкретных путей или типов файлов.
Основные применения:
- Контроль окончаний строк:
*.ps1 text eol=crlf
*.sh text eol=lf - Явное указание binary/text:
*.png binary - Фильтры (clean/smudge) — для шифрования, подстановки переменных и т.п.
- Настройка diff/merge:
*.sql diff=sql - Экспорт при
git archive:version.txt export-subst
Атрибуты применяются при индексации, merge, archive, diff и других операциях.
Git в IDE
Visual Studio Code
- Встроенная поддержка через Source Control (Ctrl+Shift+G).
- Требуется наличие
gitвPATH. - Расширения: GitLens (расширенная навигация по истории), Git Graph.
JetBrains (IntelliJ IDEA, PyCharm и др.)
- Git поддерживается «из коробки».
- Настройка: Settings → Version Control → Git → указать путь к
git.exe(на Windows). - Поддержка хуков, rebase, cherry-pick, conflict resolution в GUI.
Visual Studio
- Встроенная поддержка через Team Explorer или Git Changes (начиная с VS 2019).
- Требуется установка Git for Windows.
Eclipse
- Через плагин EGit (входит в большинство дистрибутивов).
- Ограниченная поддержка продвинутых операций; рекомендуется использовать CLI параллельно.
Советы по работе с Git
-
Пишите осмысленные сообщения коммитов:
- Первая строка — краткое описание (до 50 символов), без точки.
- Пустая строка.
- Подробное тело (если необходимо), с переносами строк
<72 символов.
-
Используйте
.gitignoreс самого начала:- Исключайте временные файлы, зависимости, IDE-настройки.
- Готовые шаблоны: github.com/github/gitignore.
-
Не коммитьте чувствительные данные:
- Используйте
.gitignore,git rm --cached, илиgit filter-repoдля очистки истории.
- Используйте
-
Предпочитайте
rebaseдля локальной истории,merge— для публичных веток. -
Регулярно синхронизируйтесь с
origin/main, чтобы избежать сложных конфликтов. -
Используйте
git config --global alias.<name> <command>для сокращения частых команд. -
Тестируйте перед коммитом: локальные хуки (
pre-commit,pre-push) снижают риск попадания ошибок в общий код. -
Избегайте
git push --forceв общих ветках; используйте--force-with-lease, если необходимо.
Внутренности .git и алиасы
Когда вы инициализируете репозиторий с помощью git init, создаётся скрытая папка .git. Это всё, что Git использует для отслеживания изменений.
| Файл/Папка | Описание |
|---|---|
| HEAD | Указывает на текущую ветку или коммит (если detached). Обычно содержит ссылку на refs/heads/<branch>. Например, refs/heads/main содержит SHA-1 последнего коммита на ветке main. |
| config | Конфигурационный файл локального репозитория (имя пользователя, remote-репозитории и т.д.). Пример содержимого: [user] name = John Doe email = john@example.com [remote "origin"] url = https://github.com/john/repo.git fetch = +refs/heads/*:refs/remotes/origin/* |
| description | Описание репозитория (используется в GUI-инструментах) |
| hooks/ | Каталог для скриптов, выполняемых при определённых событиях Git (например, pre-commit, post-merge) |
| index | Индекс (staging area) — список файлов, подготовленных к включению в следующий коммит |
| info/ | Содержит служебную информацию, например, исключения для отображения в git log |
| logs/ | Журнал изменений ссылок (refs) и HEAD |
| objects/ | Хранение всех данных репозитория: коммитов, деревьев (trees), блобов (файлов) в сжатом виде по хешам SHA-1. Файлы размещаются в подкаталогах, имена которых соответствуют первым двум символам хеша, например: objects/ab/cdef1234567890... |
| refs/ | Каталог ссылок на коммиты: ветки (refs/heads/), теги (refs/tags/), удалённые ветки (refs/remotes/) |
Git позволяет создавать алиасы для команд — чтобы упростить и ускорить работу.
git config --global alias.<alias-name> "<command>"
Примеры:
# git st → git status
git config --global alias.st "status"
# git co → git checkout
git config --global alias.co "checkout"
# git br → git branch
git config --global alias.br "branch"
# git ci → git commit
git config --global alias.ci "commit"
# git lg → красивый вывод лога
git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
# git amend → исправить последний коммит
git config --global alias.amend "commit --amend -C HEAD"
# git undo → отменить последний коммит
git config --global alias.undo "reset HEAD~1"
# git unstage → убрать файл из индекса
git config --global alias.unstage "reset HEAD --"
Алиасы хранятся в глобальном конфиге Git ~/.gitconfig или git config --global --edit.
Пример содержимого:
[alias]
st = status
co = checkout
br = branch
ci = commit
undo = reset HEAD~1
lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
Алиасы можно использовать не только для простых команд, но и для сложных сочетаний. Можно добавлять даже собственные shell-команды через !.
Особенности Git
Протоколы в Git
Git использует несколько протоколов для передачи данных между репозиториями:
- Локальный протокол (
file://) — копирование или жёсткие ссылки на объекты в пределах одной файловой системы. - HTTP(S):
- Dumb HTTP — устаревший, работает через статические файлы, не поддерживает smart-операции.
- Smart HTTP — основной современный протокол, использует
git-http-backendна сервере и позволяет выполнятьfetch,push,cloneчерез POST-запросы.
- Git-протокол (
git://) — легковесный, нешифрованный, требует запускаgit daemon. Лишён аутентификации, обычно используется только для публичного чтения. - SSH (
ssh://илиuser@host:path) — наиболее распространённый протокол для приватных репозиториев, обеспечивает шифрование и аутентификацию.
Все протоколы, кроме локального, используют упакованный обмен объектами: клиент и сервер согласуют набор необходимых объектов и передают их в сжатом виде.
Git демон
git daemon — это легковесный сервер, реализующий «голый» git://-протокол. Он:
- Слушает TCP-порт 9418.
- Предоставляет только операции чтения (clone, fetch).
- Не поддерживает аутентификацию или шифрование.
- Требует явного разрешения доступа к репозиторию (наличие файла
git-daemon-export-okв корне репозитория). - Предназначен исключительно для публичных, нечувствительных репозиториев.
В современной практике git daemon используется редко ввиду отсутствия безопасности; предпочтение отдаётся SSH или HTTPS.
Оптимизация хранения объектов в Git
Git хранит каждый объект (блоб, дерево, коммит, тег) в виде отдельного файла в .git/objects/. Однако при росте истории это становится неэффективным. Поэтому Git применяет два механизма:
- Packfiles
- Дедупликация и дельта-сжатие
Packfiles
Packfile — это бинарный файл, содержащий множество объектов Git в упакованном виде. Создаётся командами git repack или автоматически при git gc.
- Формат: заголовок + последовательность записей объектов.
- Сопутствующий файл:
.idx(индекс), содержит смещения объектов в packfile для быстрого поиска по SHA-1. - Каждый packfile может содержать базовые объекты и дельта-объекты (ссылки на другие объекты с описанием изменений).
Блобы, деревья и коммиты в Packfile
- Блобы (файлы) — кандидаты на дельта-сжатие: Git ищет похожие блобы и сохраняет только различия.
- Деревья (структуры каталогов) — также могут быть дельта-сжаты, особенно если структура каталога меняется мало.
- Коммиты — обычно не сжимаются дельтами (из-за малого размера и слабой повторяемости), но упаковываются для уменьшения количества файлов.
После упаковки исходные loose-объекты (отдельные файлы в .git/objects/) могут быть удалены.
Дедупликация данных
Git автоматически дедуплицирует идентичные данные:
- Один и тот же блоб (например, файл без изменений между коммитами) хранится один раз.
- Ссылка на блоб в деревьях — это хеш содержимого, а не путь или имя.
- Это работает на уровне объектной модели: дедупликация гарантируется хешированием содержимого (content-addressable storage).
Сжатие данных
Git применяет два уровня сжатия:
- Zlib-сжатие для каждого отдельного объекта (loose или в packfile).
- Дельта-сжатие (delta encoding) внутри packfile:
- Объект представляется как последовательность изменений относительно «базового» объекта.
- Git выбирает оптимальные базы с помощью эвристик (например, размер дельты, глубина цепочки).
- Дельты могут быть цепочечными (объект A → B → C), но Git ограничивает глубину для избежания замедления.
Ускорение доступа
Packfiles оптимизируют не только хранение, но и доступ:
- Индекс (.idx) позволяет находить объект по SHA-1 за O(log n).
- При клонировании или fetch Git передаёт один packfile, а не тысячи отдельных файлов — это снижает накладные расходы файловой системы и сети.
- Локальные операции (например,
git log) читают объекты из packfile напрямую, минуя множество мелких I/O-операций.

Как Git отслеживает изменения HEAD
Каждый раз, когда HEAD обновляется — будь то при создании коммита, переключении веток (git checkout / git switch), перемотке (git reset), слиянии или ребейзе — Git записывает новое значение HEAD в журнал reflog.
Расположение журнала:
- Для
HEAD:.git/logs/HEAD - Для веток:
.git/logs/refs/heads/<branch-name>
Каждая запись содержит:
- Хеш предыдущего состояния ссылки,
- Хеш нового состояния,
- Временную метку,
- Описание операции (например,
commit,checkout,reset,merge).
Записи reflog локальны и не передаются при push / fetch / clone.
Использование reflog для восстановления потерянных коммитов
Коммиты считаются «потерянными», если на них не ссылается ни одна ветка, тег или HEAD. Однако до момента сборки мусора (git gc) такие коммиты остаются в объектной базе и могут быть найдены через reflog.
Сценарии восстановления
-
Отменённый коммит после
reset --hardgit reset --hard HEAD~2 # ушли на 2 коммита назад, предыдущие теперь "потеряны"
git reflog # видим запись вида "HEAD@{1}: reset: ..."
git checkout -b rescue-branch HEAD@{1} # восстанавливаем через reflog -
Перезаписанная ветка после
rebaseилиfilter-branch
Reflog ветки (git reflog show <branch>) сохраняет её предыдущие состояния. -
Случайное удаление ветки
Если ветка была удалена, но ранее на неё переключались, её последнее состояние может быть в reflogHEAD.
Ограничения
- Записи reflog хранятся по умолчанию 30 дней для недостижимых (
unreachable) коммитов и 90 дней для достижимых (reachable). Эти сроки регулируются черезgc.reflogExpireиgc.reflogExpireUnreachable. - После выполнения
git gc --prune=nowнедостижимые объекты и связанные с ними записи reflog удаляются безвозвратно.
Практические команды
- Просмотр истории
HEAD:git reflog
# или эквивалентно:
git reflog show HEAD - Просмотр истории конкретной ветки:
git reflog show feature-x - Восстановление состояния по записи:
git reset --hard HEAD@{2}
# или создание новой ветки:
git branch rescue HEAD@{2}

Git-хуки: типы и назначение
Git-хуки — это исполняемые сценарии, автоматически запускаемые в ответ на определённые события в жизненном цикле репозитория. Они размещаются в директории .git/hooks/ и срабатывают локально (на стороне клиента) или на сервере (в bare-репозитории).
Основные клиентские хуки
-
pre-commit- Контекст: запускается перед фиксацией коммита, но после формирования его содержимого.
- Назначение: проверка качества кода, запуск линтеров, статических анализаторов, запрет коммита при наличии ошибок.
- Пример действия:
# .git/hooks/pre-commit
npm run lint -- --quiet
if [ $? -ne 0 ]; then
echo "Linting failed. Commit aborted."
exit 1
fi
-
post-commit- Контекст: запускается после успешного создания коммита.
- Назначение: уведомления, логирование, обновление метаданных.
- Важно: не может отменить коммит (так как тот уже зафиксирован).
- Пример действия: отправка уведомления в чат или запись в локальный журнал.
-
pre-push- Контекст: запускается перед отправкой объектов на удалённый репозиторий (
git push). - Назначение: финальная проверка кода, запрет отправки при наличии запрещённых паттернов (например,
console.log), проверка соответствия политики. - Пример действия:
# .git/hooks/pre-push
if git diff --name-only HEAD~1 | grep -q "\.env"; then
echo "Push blocked: .env files detected"
exit 1
fi
- Контекст: запускается перед отправкой объектов на удалённый репозиторий (
-
post-merge- Контекст: запускается после успешного выполнения
git mergeилиgit pull. - Назначение: обновление зависимостей, перегенерация ассетов, синхронизация конфигураций.
- Пример действия:
# .git/hooks/post-merge
if [ -f package-lock.json ]; then
npm ci
fi
- Контекст: запускается после успешного выполнения
Серверные хуки (в bare-репозитории)
pre-receive— запускается до принятия объектов от клиента; может отклонитьpushцеликом.post-receive— запускается после успешного приёма объектов; часто используется для CI/CD-триггеров, вебхуков, развёртывания.
Ограничения и особенности
- Хуки не входят в историю репозитория и не распространяются через
clone/pull. Для совместного использования их размещают в отдельной директории (например,.githooks/) и активируют черезgit config core.hooksPath. - Хуки должны быть исполняемыми (
chmod +x) и обычно написаны на shell, Python или другом скриптовом языке. - Серверные хуки работают только в bare-репозиториях (без рабочей директории).
Чистый Git-репозиторий и gitweb
Git изначально задуман как децентрализованная система контроля версий, не зависящая от веб-интерфейсов или облачных платформ. Возможна полноценная работа с репозиториями, развёрнутыми на локальном или корпоративном сервере.
Bare-репозиторий
- Не содержит рабочей директории (
working tree). - Используется исключительно как удалённое хранилище для обмена изменениями (
fetch/push). - Создаётся командой:
git init --bare my-repo.git
gitweb
- Простой веб-интерфейс для просмотра Git-репозиториев, поставляемый в комплекте с Git.
- Предоставляет: просмотр истории, diff’ы, дерево файлов, поиск по коммитам.
- Требует настройки веб-сервера (обычно Apache или Nginx с CGI).
- Не поддерживает интерактивные операции (например, pull request’ы, issue tracking) — это чисто read-only инструмент.
Альтернативы
- Для расширенной функциональности (CI/CD, code review, управление доступом) используются полноценные системы: GitLab, Gitea, Gogs, cgit.
- Однако в сценариях с повышенными требованиями к безопасности, изоляции или минимальной атакуемой поверхности часто предпочитают «голый» Git с ограниченным набором хуков и, при необходимости, gitweb для аудита.
Git команды
- git init – инициализация нового репозитория. Команда создаёт новый локальный Git-репозиторий в текущей директории. Можно открыть папку в терминале (допустим, в папке «Открыть в Терминале» или через cd), и выполнить эту команду – будет создан репозиторий, и Git начнёт отслеживать изменения в файлах. При этом будет создана скрытая папка .git, где будут храниться все метаданные репозитория.
- git status – проверка состояния репозитория. Показывает текущее состояние рабочего каталога и индекса (staging area). Отображает, какие файлы изменены, добавлены или удалены.
- git add – добавление файлов в индекс. Добавляет изменения из рабочего каталога в индекс (staging area). Это первый шаг перед созданием коммита. Например:
git add .env # Добавить конкретный файл
git add . # Добавить все изменённые файлы
- git commit – фиксация изменений. Создаёт новый коммит с изменениями из индекса. Коммит сохраняет текущее состояние проекта и добавляет сообщение, через «-m», по принципу:
git commit -m "Добавил файл – это сообщение-комментарий."
- git diff – просмотр изменений. Показывает различия между рабочим каталогом, индексом и последним коммитом.
- git log – история коммитов. Отображает историю коммитов репозитории. Можно настроить формат вывода (--oneline, --graph).
- git push – отправка изменений на удалённый репозиторий. Отправляет локальные коммиты на удалённый репозиторий. Например, чтобы отправить изменения в ветку main, нужно выполнить:
git push origin main
- git pull – получение изменений с удалённого репозитория. Загружает изменения из удалённого репозитория и объединяет их с локальной веткой. Пример:
git pull origin main
- git branch – работа с ветками. Создание, удаление и просмотр веток. Ветки позволяют работать над разными частями проекта независимо.
- git checkout – переключение между ветками. Переключается на указанную ветку или восстанавливает файлы из определённого коммита.
- git merge – слияние веток. Объединяет изменения из одной ветки в другую.
- git reset – отмена изменений. Отменяет изменения, перемещая указатель HEAD на предыдущий коммит. Может быть мягким (--soft) или жёстким (--hard).
- git rm – удаление файлов. Удаляет файлы из рабочего каталога и индекса.
- git mv – переименование или перемещение файлов в рабочем каталоге. Пример:
git mv oldname.txt newname.txt
- git stash – временное сохранение изменений (допустим для переключения на другую задачу. git stash pop – применяет последние сохранённые изменения.
- git tag – создание тегов. Создаёт теги для пометки важных моментов в истории.
- git fetch – загрузка изменений с удалённого репозитория без слияния. Важно отметить, что git pull подразумевается загрузку данных и слияние, словно git fetch+git merge. git fetch используется для просмотра данных в репозитории.
- git remote – управление удалённым репозиторием. К примеру, git remote -v показывает список удалённых репозиториев.
- git archive – создание архива текущего состояния репозитория. Пример:
git archive --format=zip --output=project.zip main
- git submodule – работа с подмодулями. Добавляет другие репозитории как подмодули текущего проекта.
- git show – просмотр информации о коммите. Показывает детали конкретного коммита.
- git shortlog – краткая история коммитов. Группирует коммиты по авторам.
- git describe – описание текущего состояния. Показывает ближайший тег и количество коммитов после него.
- git clone – клонирование репозитория. Создаёт копию удалённого репозитория на локальном компьютере.
- git config – настройка Git. Настройка параметров, к примеру, имя пользователя, email.
Команда git push --force-with-lease — это безопасная альтернатива git push --force. Она позволяет переписать историю удалённой ветки, но делает это с дополнительной проверкой, чтобы не затереть чужие изменения.
То есть команда перезаписывает только если HEAD на сервере не изменился.
Когда использовать — После git rebase или git commit --amend, когда история изменилась. — Когда работаете в команде и хотите сохранить чужие изменения. — На pull request ветках — безопаснее, чем просто --force.
Практическое задание
Установите Git.
Найдите любой открытый и безопасный репозиторий на интересном для вас языке.
Клонируйте репозиторий.
Параметры Git
В Git существуют параметры (флаги), которые можно использовать с командами для изменения их поведения. Короткие параметры начинаются с одного дефиса (-) и состоят из одной буквы. Длинные параметры начинаются с двух дефисов (--) и обычно являются полными словами. Некоторые параметры могут использоваться вместе с другими командами.
Основные параметры Git:
- -v / --verbose – добавляет больше информации в вывод команды. Часто используется для отладки или получения более подробного лога. К примеру, git push -v – подробный вывод при отправке изменений.
- -a / --all – указывает, что команда должна работать со всеми элементами (все файлы, все ветки). Пример – git add -A добавит все изменения, включая удалённые файлы, git branch -a – показать все ветки (локальные и удалённые).
- -m / --message – используется для добавления сообщения к коммиту.
- --amend – позволяет изменить последний коммит, например, добавить забытые изменения, или исправить сообщения.
- --force / -f – принудительно выполняет действие, даже если это может привести к потере данных. Пример – git push –force принудительно отправит изменения на удалённый репозиторий.
- --global – применяет настройку ко всем репозиториям пользователя (глобально).
- --local применяет настройку только к текущему репозиторию (локально).
- --help показывает справку по команде или параметру.
- --oneline показывает историю коммитов в компактной формате.
- --graph отображает графическое представление веток и коммитов.
- --hard – удаляет все изменения без возможности восстановления.
- --soft - сохраняет изменения в рабочем каталоге при выполнении команды reset.
- --cached - работает с индексом (staging area) без изменения рабочего каталога.
- --dry-run показывает, что произойдёт при выполнении команды, но не выполняет её.
- --tags - включает теги при выполнении команды.
- --recurse-submodules - работает с подмодулями рекурсивно.
- --patch / -p позволяет интерактивно выбирать части изменений для добавления в индекс.
- --follow следует за историей файла, даже если он был переименован.
- --no-ff - запрещает fast-forward слияние, чтобы сохранить историю ветки.
- --squash - объединяет все коммиты из ветки в один при слиянии.
- --rebase перебазирует изменения вместо слияния.
Самый важный для новичка - --help. Всегда можно получить дополнительную информацию о конкретной команде или параметре. Пример - git commit --help.
Отличия SVN от Git
В некоторых случаях используется SVN (Apache Subversion), в отличие от Git, это централизованная система контроля версий, требующая установки сервера.
Доступ к SVN осуществляется через протоколы:
- svn:// (собственный протокол);
- http:// или https:// (через веб-сервер);
- file:// (локальный доступ).
В SVN вся история хранится на сервере, и разработчики имеют только рабочую копию. Команды похожие, позволяют тоже скачать клон, получить свежие изменения и отправить изменения на сервер.
Отличия SVN от Git
| Характеристика/команда | SVN | Git |
|---|---|---|
| Архитектура | Централизованная | Децентрализованная |
| Полная история | На сервере | У каждого разработчика |
| Работа офлайн | Нет | Да |
| Ветвление | Медленное (копируются папки) | Быстрое (используются указатели на коммиты) |
| Конфликты | Чаще (блокировки файлов) | Реже (слияние через коммиты) |
| Размер репозитория | Огромный | Компактный (за счёт дельта-компрессии) |
| Клонирование репозитория | svn checkout <URL> | git clone <URL> |
| Обновление локальной копии | svn update | git pull (fetch + merge) |
| Отправка изменений | svn commit | git push |
| Добавление файла | svn add <file> | git add <file> |
| Удаление файла | svn delete <file> | git rm <file> |
| Фиксация изменений | svn commit -m "message" | git commit -m "message" |
| Слияние веток | svn merge <URL> | git merge <branch> |
| Создание ветки | svn copy <URL>/trunk <URL>/branches/<name> | git branch <name> + git push |
| Переключение ветки | svn switch <URL>/branches/<name> | git checkout <branch> |
| Просмотр истории | svn log | git log |
| Отмена изменений | svn revert <file> | git restore <file> |
| Метки (теги) | svn copy <URL>/trunk <URL>/tags/v1.0 | git tag v1.0 |
| Игнорирование файлов | svn:ignore | .gitignore |
| Конфликты | svn resolve | git mergetool |
Защита данных
Мы изучили особенности защиты кода. Но как поступают с данными? Для данных нет Git – в гите только код, а данные представляют собой порой огромный объем информации. Но риски бывают те же – удаление, повреждение, изменение, засорение.
Для защиты данных используется резервное копирование (backup, бэкап), это защищает от пропажи данных при сбоях, атаках или ошибках.
Бэкапы баз данных осуществляются по следующим методам:
| Метод | Описание |
|---|---|
| Полный бэкап | Копируется вся база данных (дамп) |
| Инкрементный | Копируются только изменения с момента последнего бэкапа |
| Транзакционные логи | Записываются все изменения |
| Снимки (snapshots) | Полный снимок диска |
Транзакционные логи – журналы всех изменений в БД, которые позволяют восстанавливать данные до момента сбоя, синхронизировать реплики и анализировать историю операций. То есть, при любом изменении в БД, СУБД автоматически записывает сначала операцию в лог, только затем применяет изменения к данным. Примеры:
| СУБД | Лог | Применение |
|---|---|---|
| PostgreSQL | WAL (Write-Ahead Log) | Восстановление, репликация, PITR |
| MySQL | Binlog (Binary Log) | Репликация, восстановление, аудит |
| SQL Server | Transaction Log | PITR, зеркалирование |
| MongoDB | Oplog (Operations Log) | Репликация в шардированных кластерах |
Обычно при резервном копировании БД пишут скрипт, который потом запускают по необходимости. Например, в PostgreSQL пишут pg_dump для полного бэкапа. Для автоматизации можно использовать планировщики задач (допустим, встроенный планировщик задач в Windows), которые будут по расписанию запускать этот исполняемый файл, в котором указана команда для бэкапа.
Бэкапы файлов и программ (документов, конфигураций):
| Метод | Описание |
|---|---|
| Полный бэкап | Копируется вся папка / все файлы |
| Инкрементный | Только новые или изменённые файлы |
| Дифференциальный | Все изменения с момента последнего полного бэкапа |
Для резервного копирования файлов можно использовать инструменты:
- rsync – синхронизация файлов;
- borg / restic – инкрементные бэкапы с шифрованием;
- tar + gzip – упаковка в архив.
Таким образом, для автоматизации бэкапов используется алгоритм:
- Планировщик (cron, system-timer) запускает скрипт;
- Скрипт создаёт бэкап (дамп БД, копия файлов);
- Проверка (если бэкап битый – отправляется предупреждение);
- Ротация (старые бэкапы могут удаляться по правилам).
Но если с порядком всё понятно, то где хранить эти бэкапы?
Как можно заметить, файлы, в отличие от кода, требуют заметно больше ресурсов – места в хранилище. Допустим, если каталог файлов вложений весит 1 ТБ, и делать каждый день полный бэкап, то за месяц улетит уже 30 ТБ места! К тому же, если хранить на том же диске, то при повреждении диска или сервера, смысла от бэкапов не будет – они повредились вместе с оригиналом, поэтому важно определить, где хранить:
- на другом диске того же сервера;
- на другом сервере;
- на специально выделенном сервере-хранилище бэкапов;
- в облаке (допустим AWS S3, Wasabi);
- локально (если серверу конец – конец и данным).
Как восстанавливать данные из бэкапов?
БД восстанавливается средствами СУБД. Главное иметь выгруженный дамп, а дальше уже встроенными инструментами выполнить restore (восстановление).
Файлы же восстанавливаются обычным копированием/распаковкой.
Важно: рекомендуется также ограничить права доступа к бэкапа, чтобы они были неизменяемыми.
Таким образом, защита данных в первую очередь включает в себя:
- RAID - система защиты от отказа дисков.
- Бэкапы - ежедневные/почасовые резервные копии.
- DRP (Disaster Recovery Plan) - полный план восстановления после катастрофы.
- Репликация БД - горячий резерв.
- Балансировка нагрузки позволит распределить трафик между серверами.
- Кластеризация - это высокая доступность через несколько нодов (позже ещё об этом поговорим.